package cn.edu360.lucene;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zx on 2017/9/12.
 * <p>
 * Lucene Index ToolBox : https://github.com/DmitryKey/luke/releases
 * <p>
 * https://segmentfault.com/a/1190000010367206
 */
public class HelloWorld {
    public static String INDEX_PATH = "C:/lucene/index";

    public static void writeToLucene(String indexPath, Analyzer analyzer, List<Document> documentList) throws Exception {
        FSDirectory fsDirectory = FSDirectory.open(Paths.get(indexPath));
        //写入索引的配置，设置了分词器
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        //指定了写入数据目录和配置
        IndexWriter indexWriter = new IndexWriter(fsDirectory, indexWriterConfig);
        //通过IndexWriter写入文档对象
        for (Document document : documentList) {
            indexWriter.addDocument(document);
        }
        indexWriter.close();
    }

    public static List<Document> readFromLucene(String indexPath, Query query) throws Exception {

        FSDirectory fsDirectory = FSDirectory.open(Paths.get(indexPath));
        DirectoryReader directoryReader = DirectoryReader.open(fsDirectory);
        //索引查询器
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
        TopDocs topDocs = indexSearcher.search(query, 10);
        //获取到查找到的文文档ID和得分
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        List<Document> list = new ArrayList<>(scoreDocs.length);
        for (ScoreDoc scoreDoc : scoreDocs) {
            int docID = scoreDoc.doc; //从索引中查询到文档的ID，
            Document document = indexSearcher.doc(docID); //在根据ID到文档中查找文档内容
            list.add(document);
        }
        directoryReader.close();
        return list;

    }


    /**
     * 往用lucene写入数据
     *
     * @throws IOException
     */
    @Test
    public void testCreate() throws Exception {
        String indexPath = INDEX_PATH;

        //分词器
        Analyzer analyzer = new StandardAnalyzer();//标准分词器，一个字分一次。
//        Analyzer analyzer = new IKAnalyzer(true);

        List<Document> documentList = new ArrayList<>();

        Book book = new Book();
        book.setId(1L);
        book.setTitle("Java从入门到精通");
        book.setAuthor("老王");
        book.setContent("从初学者角度出发，详细介绍了使用Java语言进行程序开发需要掌握的知识.");
        book.setPrice(100d);
        book.setUrl("http://www.edu360.cn/a10011");
        documentList.add(book.toDocument());

        book = new Book();
        book.setId(2L);
        book.setTitle("Java开发手册");
        book.setAuthor("老李");
        book.setContent("中国人自己原创的Java编程规范，希望未来社会发展的每一行代码都规范、合理、高效。");
        book.setPrice(105.5d);
        book.setUrl("http://product.dangdang.com/27444749.html");
        documentList.add(book.toDocument());

        book = new Book();
        book.setId(3L);
        book.setTitle("Java核心技术");
        book.setAuthor("老李");
        book.setContent("Java领域极具影响力和价值的著作之一，与《Java编程思想》齐名，10余年全球畅销不衰.");
        book.setPrice(300d);
        book.setUrl("http://product.dangdang.com/24035306.html");
        documentList.add(book.toDocument());

        book = new Book();
        book.setId(4L);
        book.setTitle("JavaScript从入门到精通");
        book.setAuthor("老王");
        book.setContent("JavaScript高级程序设计视频讲解，web开发核心技术案例实战.");
        book.setPrice(50.5d);
        book.setUrl("http://product.dangdang.com/25108304.html");
        documentList.add(book.toDocument());

        book = new Book();
        book.setId(5L);
        book.setTitle("JavaScript权威指南");
        book.setAuthor("王小二");
        book.setContent("淘宝前端团队倾情翻译！经典权威的JavaScript犀牛书");
        book.setPrice(88.8d);
        book.setUrl("http://product.dangdang.com/22722790.html");
        documentList.add(book.toDocument());

        writeToLucene(indexPath, analyzer, documentList);


    }

    @Test
    public void testSearch() throws Exception {

        String indexPath = INDEX_PATH;
        //分词器
        Analyzer analyzer = new StandardAnalyzer();
//        Analyzer analyzer = new IKAnalyzer(true);
        //查询条件解析器
        QueryParser queryParser = new QueryParser("content", analyzer);
        //对查询条件进行解析
        Query query = queryParser.parse("Script");


        List<Document> list = readFromLucene(indexPath, query);
        for (Document document : list) {
            Book book = Book.parseArticle(document);
            System.out.println(book.toString());

        }


        //TermQuery将查询条件当成是一个固定的词
        //Query query = new TermQuery(new Term("url", "http://www.edu360.cn/a10010"));
        //在【索引】中进行查找

    }

    @Test
    public void testDelete() throws IOException, ParseException {

        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        Analyzer analyzer = new IKAnalyzer(true);
        FSDirectory fsDirectory = FSDirectory.open(Paths.get(indexPath));
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(fsDirectory, indexWriterConfig);

        //Term词条查找，内容必须完全匹配，不分词
        //indexWriter.deleteDocuments(new Term("content", "学好"));

        //QueryParser parser = new QueryParser("title", analyzer);
        //Query query = parser.parse("大数据老师");

        //LongPoint是建立索引的
        //Query query = LongPoint.newRangeQuery("id", 99L, 120L);
        Query query = LongPoint.newExactQuery("id", 105L);

        indexWriter.deleteDocuments(query);

        indexWriter.commit();
        indexWriter.close();
    }

    /**
     * lucene的update比较特殊，update的代价太高，先删除，然后在插入
     *
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void testUpdate() throws IOException, ParseException {

        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        StandardAnalyzer analyzer = new StandardAnalyzer();
        FSDirectory fsDirectory = FSDirectory.open(Paths.get(indexPath));
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(fsDirectory, indexWriterConfig);


        Book book = new Book();
        book.setId(106L);
        book.setAuthor("老王");
        book.setTitle("学好大数据，要找赵老师");
        book.setContent("迎娶白富美，走上人生巅峰！！！");
        book.setUrl("http://www.edu360.cn/a111");
        Document document = book.toDocument();

        indexWriter.updateDocument(new Term("author", "老王"), document);

        indexWriter.commit();
        indexWriter.close();
    }

    /**
     * 可以从多个字段中查找
     *
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void testMultiField() throws IOException, ParseException {

        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        Analyzer analyzer = new IKAnalyzer(true);
        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);

        String[] fields = {"title", "content"};
        //多字段的查询转换器
        MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
        Query query = queryParser.parse("老师");

        TopDocs topDocs = indexSearcher.search(query, 10);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = indexSearcher.doc(doc);
            Book book = Book.parseArticle(document);
            System.out.println(book);
        }

        directoryReader.close();
    }

    /**
     * 查找全部的数据
     *
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void testMatchAll() throws IOException, ParseException {

        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);

        Query query = new MatchAllDocsQuery();

        TopDocs topDocs = indexSearcher.search(query, 10);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = indexSearcher.doc(doc);
            Book book = Book.parseArticle(document);
            System.out.println(book);
        }

        directoryReader.close();
    }

    /**
     * 布尔查询，可以组合多个查询条件
     *
     * @throws Exception
     */
    @Test
    public void testBooleanQuery() throws Exception {
        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);

        Query query1 = new TermQuery(new Term("title", "老师"));
        Query query2 = new TermQuery(new Term("content", "丁"));
        BooleanClause bc1 = new BooleanClause(query1, BooleanClause.Occur.MUST);
        BooleanClause bc2 = new BooleanClause(query2, BooleanClause.Occur.MUST_NOT);
        BooleanQuery boolQuery = new BooleanQuery.Builder().add(bc1).add(bc2).build();
        System.out.println(boolQuery);

        TopDocs topDocs = indexSearcher.search(boolQuery, 10);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = indexSearcher.doc(doc);
            Book book = Book.parseArticle(document);
            System.out.println(book);
        }

        directoryReader.close();
    }

    @Test
    public void testQueryParser() throws Exception {
        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);

        //创建一个QueryParser对象。参数1：默认搜索域 参数2：分析器对象。
        QueryParser queryParser = new QueryParser("title", new IKAnalyzer(true));

        //Query query = queryParser.parse("数据");
        Query query = queryParser.parse("title:学好 OR title:学习");
        System.out.println(query);

        TopDocs topDocs = indexSearcher.search(query, 10);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = indexSearcher.doc(doc);
            Book book = Book.parseArticle(document);
            System.out.println(book);
        }

        directoryReader.close();
    }


    @Test
    public void testRangeQuery() throws Exception {
        String indexPath = "/Users/zx/Documents/dev/lucene/index";
        DirectoryReader directoryReader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
        IndexSearcher indexSearcher = new IndexSearcher(directoryReader);


        Query query = LongPoint.newRangeQuery("id", 107L, 108L);

        System.out.println(query);

        TopDocs topDocs = indexSearcher.search(query, 10);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;
            Document document = indexSearcher.doc(doc);
            Book book = Book.parseArticle(document);
            System.out.println(book);
        }

        directoryReader.close();
    }
}
